"""
Copyright 2009 Texas A&M University
 
Licensed under the Apache License, Version 2.0 (the "License"); you may not use 
this file except in compliance with the License. You may obtain a copy of the 
License at

http://www.apache.org/licenses/LICENSE-2.0
  
Unless required by applicable law or agreed to in writing, software distributed 
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY KIND, either express or implied. See the License for the 
specific language governing permissions and limitations under the License. 
"""

from logging import getLogger

import zope.interface

from metalib.interfaces import IMetalibGroup, IMetalibSession
from metalib.exceptions import *

try:
    from xml.etree import cElementTree as etree
except ImportError:
    from xml.etree import ElementTree as etree



__all__ = ['MetalibGroup']

log = getLogger('metalib.group')

class MetalibGroup(object):
    zope.interface.implements(IMetalibGroup)
    
    def __init__(self, session, id):
        self._session = IMetalibSession(session)
        self._id = id
    
    def post(self, operation, **kwargs):
        """ Post to the connection/session that this group was created from, 
        add the required group information into the post data """
        kwargs.setdefault('group_number',self._id)
        return self._session.post(operation,**kwargs)
    
    def status(self):
        """ Wrapper for find_group_info """
        response = self.post('find_group_info_request')
          
        fstatuses = response.findall ('find_group_info_response/base_info/find_status')
        if fstatuses is not None:
          fs = {'total': 0, 'donetotal': 0}
          for fstatus in fstatuses:
              if fstatus.text in fs:
                  fs[fstatus.text] += 1
              else:
                  fs[fstatus.text] = 1
              if (fstatus.text == 'DONE' or fstatus.text == 'DONE1' or 
                 fstatus.text == 'DONE2' or fstatus.text == 'DONE3'):
                  fs['donetotal'] += 1
              fs['total'] += 1
          print fs
          return fs

        elif (response.find('*/local_error') is not None):
            error_code = response.find('*/local_error/error_code').text
            error_msg = response.find('*/local_error/error_text').text
            raise MetalibServerException(error_code, error_msg)

        #TODO: Handle an invalid xml response (non-error)
        raise MetalibException(etree.tostring(response))
    
    def merge_sort(self, action, sort_key=None, secondary_sort_key=None,
                   fetch_more=None, application=None):
        """ Action should be one of ['merge', 'merge_more', 'merge_more_set', 'remerge', 'sort_only'] """
        
        if action not in ['merge', 'merge_more', 'merge_more_set', 'remerge', 'sort_only']:
            raise MetalibException ('Invalid merge action')
        
        param = {'action':action}
        if sort_key is not None:
            param['primary_sort_key'] = sort_key
        if secondary_sort_key is not None:
            param['secondary_sort_key'] = secondary_sort_key
        if fetch_more is not None:
            param['fetch_more_records'] = fetch_more
        if application is not None:
            param['calling_application'] = application
        
        response = self.post('merge_sort_request', **param)            
        setnumber = response.find('merge_sort_response/new_set_number')
        numdocs = response.find('merge_sort_response/no_of_documents')
        res = {}
        if setnumber is not None and numdocs is not None:
            res['setnumber'] = setnumber.text
            res['numdocs'] = numdocs.text
            return res
            
        if (response.find('*/local_error') is not None):
            error_code = response.find('*/local_error/error_code').text
            error_msg = response.find('*/local_error/error_text').text
            raise MetalibServerException(error_code, error_msg)

        #TODO: Handle an invalid xml response (non-error)
        raise MetalibException(etree.tostring(response))
            